home *** CD-ROM | disk | FTP | other *** search
- /*
- Suggest appropriate values for the TIME_ADJUST constant.
-
- source: measure.c
- started: August 2, 1989
- version: see below
-
- By setting the TIME_ADJUST constant to the value proposed by this
- program, you should more accurate timing statistics.
-
- The TIME_ADJUST constant is used only in the sl_adjust() function
- in Sherlock.c. It is used to subtract the "unmeasured overhead"
- caused by calling and returning from Sherlock support routines.
- This program measures this "unmeasured overhead" by calling dummy
- Sherlock routines and counting the ticks that result.
-
- WARNING: This program defines a value for sl_speed, which must match
- the value of sl_speed used in sherlock.c in order for this program
- to give a reasonable suggestion for the value of TIME_ADJUST.
- By default, sl_speed is initialized to 55 in this file and in
- sherlock.c. This program prints the value of sl_speed right after
- signing on.
-
- The units of TIME_ADJUST are ticks per 1000 "average" calls to
- Sherlock macros. Since there is no way to determine exactly what
- an average call really is, using TIME_ADJUST will probably not produce
- perfect statistics.
-
- The sl_adjust() routine in sherlock.c handles the details of adjusting
- the statistics based on TIME_ADJUST. The TIME_ADJUST constant does not
- affect the gathering of statistics in any way, just the way that
- sl_dump() reports the statistics already gathered.
-
- Exactly one of the constants FAR_MODEL and NEAR_MODEL should be
- #defined on the command line of this program. The program M1.EXE
- should be compiled with NEAR_MODEL #defined. The program M2.EXE
- should be compiled with FAR_MODEL #defined.
-
- The values reported by M1.EXE and M2.EXE will be different. Modify the
- make files for the tiny, small and compact models to use the value
- suggested by M1.EXE. Modify the make files for the medium, large and
- huge memory model to the value suggested by M2.EXE. The make files
- distributed with Sherlock use 0 for TIME_ADJUST, as follows:
-
- -DTIME_ADJUST=0 Turbo C
- /DTIME_ADJUST=0 MicroSoft C
-
- Both M1.EXE and M2.EXE suggest two values for TIME_ADJUST,
- one value for when using the preferred macros and one value for
- when using the alternate macros. Make sure to use to proper value.
-
- In the interest of getting the best statistics, several routines below
- are passed parameters that are never used, or assign values to
- variables which are never used. The Turbo C compiler will issue
- warnings about such matters, and those warnings can safely be ignored.
- The -w-aus and -w-par compiler options are used to suppress these
- warnings in measure.mak.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <process.h>
- #include <string.h>
- #include <ctype.h>
-
- #define VERSION "August 4, 1989\n"
-
- /*
- WARNING! This value of sl_speed should match that in sherlock.c!
- */
- int sl_speed = 55;
- unsigned long sl_count = 0;
-
- #define TRUE (1)
- #define FALSE (0)
- #define BAD_EXIT (1)
-
- /*
- Define data structure used by the dummy Sherlock routines.
- */
- struct stat {
- struct stat * next; /* pointer to next bucket. */
- struct stat * alpha; /* alphabetical list. */
- char * name; /* pointer to checkpoint name. */
- long n_stat; /* # of calls to macros. */
- long n_disable; /* # of prints to skip or 0. */
- long n_times; /* # of profiler ticks. */
- long n_2times; /* Cumulative ticks. */
- long n_ftime; /* single execution time. 8/3/89 */
- int trace; /* trace flag. */
- };
- struct stat a_list;
-
- #define MAX_STAT 500
- struct stat sl__nodes [MAX_STAT]; /* Static node table. */
- int cur_stat = 0;
-
- #define MAX_BUG_LEVEL 100
- struct stat * call_stack [MAX_BUG_LEVEL];
- int sl_level = 0;
-
- #define MAX_HASH 241
- struct stat * hash_tab [MAX_HASH];
- struct stat * wildcard = NULL; /* Head of wildcard list. */
- int troff = FALSE; /* TRUE if all tracing disabled. */
- char * check_s = NULL; /* Name of current macro. */
- long disable = 0; /* Local disable count. */
- long g_disable = 0; /* Global disable printing counter. */
-
- unsigned long t_check = 0;
- unsigned long t_find = 0;
- unsigned long t_new = 0;
-
- /*
- Function prototypes for dummy Sherlock routines.
- */
- int sl_ret (void);
- int sl_visit (struct stat *p, int stat_flag, int entry_flag);
- int sl1trace (char * name);
- int sl2trace (struct stat ** h, char * name);
-
- void sl_check (char *);
- struct stat * sl_find (char *, char *);
- int sl_hash (char *);
- int prefix (char *, char *);
- struct stat * sl_new (char *);
- void sl_init (char *);
- void sl_cout (char);
- void sl_sout (char *);
- void sl_s2out (char *, char *);
- void sl_s3out (char *, char *, char *);
- void sl_slout (int, char *);
- int sl_visit (struct stat *, int, int);
- int has_wild (char *);
- int is_match (char *, char *);
- int strcmp_ (char *, char *);
- int streq_ (char *, char *);
-
- /*
- Dummy Sherlock macros.
- */
- #define TRACEPB2(a) {static struct stat *h=0; if(sl2trace(&h,a)) {}}
- #define TRACEPB1(a) if(sl1trace(a)) {}
-
- /*
- Execute a loop 1000 times, both with and without Sherlock macros.
- Report the difference in clock ticks.
- */
- main()
- {
- int i;
- unsigned long sl_fast, sl_slow;
-
- /* Make sure exactly one of FAR_MODEL or NEAR_MODEL is defined. */
-
- #ifndef FAR_MODEL
- #ifndef NEAR_MODEL
- printf("Please #define NEAR_MODEL or FAR_MODEL");
- exit(BAD_EXIT);
- #endif
- #endif
-
- #ifdef FAR_MODEL
- #ifdef NEAR_MODEL
- printf("Please #define only one of NEAR_MODEL or FAR_MODEL");
- exit(BAD_EXIT);
- #endif
- #endif
-
- /* Sign on. */
-
- #ifdef NEAR_MODEL
- printf("m1: %s", VERSION);
- #endif
-
- #ifdef FAR_MODEL
- printf("m2: %s", VERSION);
- #endif
-
- /* Print speed up factor. */
- printf("sl_speed = %d\n", sl_speed);
-
- sl_init("dummy version");
-
- /* Part I: for preferred macros. */
-
- /* Calculate 1000 times the Sherlock overhead. */
- sl_count = 0;
- for(i = 0; i < 1000; i++) {
- dummy(i);
- }
- sl_fast = sl_count;
-
- sl_count = 0;
- for(i = 0; i < 1000; i++) {
- TRACEPB2("count");
- dummy(i);
- sl_ret();
- }
- sl_slow = sl_count;
-
- #if 0
- printf("sl_slow: %ld, sl_fast: %ld ", sl_slow, sl_fast);
- printf("t_check: %ld, t_find: %ld, t_new: %ld\n",
- t_check, t_find, t_new);
- #endif
-
- #ifdef FAR_MODEL
- printf("Set TIME_ADJUST (far code models, preferred macros) to %d\n",
- (sl_slow - sl_fast));
- #endif
-
- #ifdef NEAR_MODEL
- printf("Set TIME_ADJUST (near code models, preferred macros) to %d\n",
- (sl_slow - sl_fast));
- #endif
-
- /* Part II: Alternate macros. */
- t_check = 0;
- t_find = 0;
- t_new = 0;
-
- /* Calculate 1000 times the Sherlock overhead. */
- sl_count = 0;
- for(i = 0; i < 1000; i++) {
- dummy(i);
- }
- sl_fast = sl_count;
-
- sl_count = 0;
- for(i = 0; i < 1000; i++) {
- TRACEPB1("count");
- dummy(i);
- sl_ret();
- }
- sl_slow = sl_count;
-
- #if 0
- printf("sl_slow: %ld, sl_fast: %ld ", sl_slow, sl_fast);
- printf("t_check: %ld, t_find: %ld, t_new: %ld\n",
- t_check, t_find, t_new);
- #endif
-
- #ifdef FAR_MODEL
- printf("Set TIME_ADJUST (far code models, alternate macros) to %d\n",
- (sl_slow - sl_fast));
- printf("Far code models: medium, large, huge. Use prffar.obj\n");
- #endif
-
- #ifdef NEAR_MODEL
- printf("Set TIME_ADJUST (near code models, alternate macros) to %d\n",
- (sl_slow - sl_fast));
- printf("Near code models: tiny, small, compact. Use prfnear.obj\n");
- #endif
-
- }
-
- int global_var;
-
- /*
- A do-nothing routine that may prevent some unwanted loop optimizations.
- The speed of this routine does not affect the value of TIME_ADJUST.
- */
- dummy(i)
- int i;
- {
- global_var++;
- }
-
- /*
- The following routines are taken from sherlock.c.
- */
- void
- sl_check(register char *s)
- {
- register char c;
- register int i;
- char sbuf [40];
- char *old_s;
-
- t_check++;
-
- old_s = s;
-
- /* Check for null string. */
- if (!*s) {
- /* Write the error message. */
- sprintf(sbuf, "%p", s);
- sl_s3out("sl_check: ", check_s, ": null string @ ");
- sl_s2out(sbuf, "\n");
- exit(BAD_EXIT);
- }
-
- /* 6/27/89: allow up to 31 character names. */
- for (i = 0; i < 31; i++) {
- c = *s++;
- if (c == '\0') {
- return ;
- }
-
- /* Allow only identifiers and wild cards. */
- if (!isalnum(c) && c != '_' && c != '*' && c != '?') {
- sprintf(sbuf, "%p", s);
- sl_s3out("sl_check: ", check_s, ": bad character: ");
- sl_cout(c);
- sl_s3out(" in ", old_s, " @ ");
- sl_s2out(sbuf, "\n");
- exit(BAD_EXIT);
- }
- }
- sprintf(sbuf, "%p", s);
- sl_s3out("sl_check: ", check_s, ": run on argument: ");
- sl_s3out(old_s, " @ ", sbuf);
- sl_sout("\n");
- exit(BAD_EXIT);
- }
-
- struct stat *
- sl_find(char *macro_type, char *s)
- {
- register int i;
- register struct stat *p, *q, *node;
- register int hash;
-
- t_find++;
-
- /* Update global error string. */
- check_s = macro_type;
-
- /* Search the proper index table. */
- hash = sl_hash(s);
- p = hash_tab [hash];
- if (p != NULL) {
- i = strcmp_(s, p -> name);
- if (i == 0) {
- return p;
- }
- }
- if (p == NULL || i < 0) {
- sl_check(s);
- node = sl_new(s);
- hash_tab [hash] = node;
- node -> next = p;
- node -> n_disable = disable;
- return node;
- }
-
- /* Search the list for the node. */
- for (q = p, p = p -> next; p; q = p, p = p -> next) {
- i = strcmp_(s, p -> name);
- if (i == 0) {
- return p;
- }
- else if (i < 0) {
- break;
- }
- }
-
- /* Not found. */
- sl_check(s);
- node = sl_new(s);
- q -> next = node;
- node -> next = p;
- node -> n_disable = disable;
- return node;
- }
-
- int
- sl_hash(register char *s)
- {
- register unsigned int hash;
-
- for (hash = 0; *s; ) {
- hash += hash + hash + (unsigned int) *s++;
- hash %= MAX_HASH;
- }
- return (int) hash;
- }
-
- struct stat *
- sl_new(char *s)
- {
- register struct stat * node, *p;
-
- t_new++;
-
- /* Not found. Point node at a new node. */
- if (cur_stat >= MAX_STAT) {
- sl_sout("sl_new: trace table overflow\n");
- exit(BAD_EXIT);
- }
-
- /* Create the new node. */
- node = sl__nodes + cur_stat;
- cur_stat++;
- node -> name = s;
- node -> n_stat = 0;
- node -> n_disable = disable;
-
- /*
- Search the wildcard list for a node which matches s.
- If found. Set trace field.
- */
- for (p = wildcard; p; p = p -> next) {
- if (is_match(p -> name, s)) {
- node -> trace = p -> trace;
- return node;
- }
- }
-
- /* No match. */
- node -> trace = 0;
- return node;
- }
-
- int
- has_wild(register char *s)
- {
- register char c;
-
- for (;;) {
- c = *s++;
- if (c == '\0') {
- return FALSE;
- }
- else if (c == '*' || c == '?') {
- return TRUE;
- }
- }
- }
-
- int
- is_match(register char *s1, register char *s2)
- {
- register char c;
-
- for (;;) {
- c = *s1++;
- if (c == '\0') {
- return !*s2;
- }
- else if (c == '*') {
- /* Matches zero or more characters. */
- return TRUE;
- }
- else if (c == '?') {
- /* Matches exactly one character. */
- if (*s2 == '\0') {
- return FALSE;
- }
- else {
- s2++;
- }
- }
- else if (c != *s2++) {
- return FALSE;
- }
- }
- }
-
- int
- prefix(char *p, char *s)
- {
- while (*p) {
- if (*p++ != *s++) {
- return FALSE;
- }
- }
- return TRUE;
- }
-
- int
- strcmp_(register char *s1, register char *s2)
- {
- while (*s1 == *s2) {
- if (*s1 == '\0') {
- return 0;
- }
- else {
- s1++;
- s2++;
- }
- }
- return ((int) *s1) - ((int) *s2);
- }
-
- int
- streq_(register char *s1, register char *s2)
- {
- while(*s1) {
- if (*s1++ != *s2++) {
- return FALSE;
- }
- }
- return !*s2;
- }
-
- void
- sl_init(char * version)
- {
- int i;
-
- /* Initialize the hash table. */
- for (i = 0; i < MAX_HASH; i++) {
- hash_tab [i] = NULL;
- }
- a_list.alpha = NULL;
- a_list.next = NULL;
- a_list.name = NULL;
-
- sl_von();
- }
-
- void
- sl_cout(char c)
- {
- putchar(c);
- }
-
- void
- sl_sout(char *s)
- {
- while (*s) {
- sl_cout(*s++);
- }
- }
-
- void
- sl_s2out(char *s1, char *s2)
- {
- sl_sout(s1);
- sl_sout(s2);
- }
-
- void
- sl_s3out(char *s1, char *s2, char *s3)
- {
- sl_sout(s1);
- sl_sout(s2);
- sl_sout(s3);
- }
-
- /*
- The following routines have been modified from
- corresponding routines in sherlock.c.
-
- The purpose of the modifications is to measure only the
- code that contributes to "unmeasured overhead."
-
- In the case of the preferred macros, some arbitrary guesses
- have been made about the frequency of multiple calls to the
- same tracepoint name, which will affect the number of times
- sl_find() should be counted. If my assumptions seem unreasonable,
- try your own.
- */
-
- int sl_mod = 0;
-
- /* The unmeasured portion of sl2trace. */
- int
- sl2trace(struct stat **pp, char *s)
- {
- /* Force a call to sl_find every 5th call. */
- if (sl_mod++ == 5) {
- *pp = sl_find("TRACEP2", s);
- sl_mod = 0;
- sl_new(s);
- }
- sl_visit(*pp, 1, 1);
- return TRUE;
- }
-
- /* The unmeasured portion of sl1trace. */
- int
- sl1trace(char *s)
- {
- struct stat * pp;
-
- pp = sl_find("TRACEP1", s);
-
- /* Force a call to sl_new every 5th call. */
- if (sl_mod++ == 5) {
- sl_mod = 0;
- sl_new(s);
- }
- sl_visit(pp, 1, 1);
- return TRUE;
- }
-
- /* The unmeasured portion of sl_visit */
- int
- sl_visit(struct stat *p, int stat_flag, int entry_flag)
- {
- }
-
- /* The unmeasured portion of sl_ret */
- int
- sl_ret()
- {
- if (g_disable > 0) {
- ;
- }
- else if (g_disable > 0) {
- ;
- }
- else {
- return TRUE;
- }
- }
-